package bs4

import (
	"strings"

	"gitee.com/baixudong/gospider/tools"
	"github.com/PuerkitoBio/goquery"
)

// 文档树操作========================================================================= start
type Client struct {
	object  *goquery.Selection
	baseUrl string
}

// 创建一个文档树
func NewClient(txt string, baseUrl ...string) *Client {
	html, err := goquery.NewDocumentFromReader(strings.NewReader(txt))
	if err != nil {
		return nil
	}
	if html.Size() < 1 {
		return nil
	}
	cli := &Client{object: html.Eq(0)}
	if len(baseUrl) > 0 {
		cli.baseUrl = baseUrl[0]
	}
	return cli
}

// 寻找一个节点
func (obj *Client) Find(election string) *Client {
	rs := obj.object.Find(election)
	if rs.Size() > 0 {
		return &Client{object: rs.Eq(0), baseUrl: obj.baseUrl}
	}
	return nil
}

// 寻找多个节点
func (obj *Client) Finds(election string) []*Client {
	ll := []*Client{}
	rs := obj.object.Find(election)
	for i := 0; i < rs.Size(); i++ {
		ll = append(ll, &Client{object: rs.Eq(i), baseUrl: obj.baseUrl})
	}
	return ll
}

// 寻找下一个节点
func (obj *Client) Next(election ...string) *Client {
	if len(election) == 0 {
		return &Client{object: obj.object.Next(), baseUrl: obj.baseUrl}
	} else {
		return &Client{object: obj.object.NextFiltered(election[0]), baseUrl: obj.baseUrl}
	}
}

// 寻找之后的所有节点
func (obj *Client) Nexts(election ...string) []*Client {
	ll := []*Client{}
	var rs *goquery.Selection
	if len(election) == 0 {
		rs = obj.object.NextAll()
	} else {
		rs = obj.object.NextAllFiltered(election[0])
	}
	for i := 0; i < rs.Size(); i++ {
		ll = append(ll, &Client{object: rs.Eq(i), baseUrl: obj.baseUrl})
	}
	return ll
}

// 寻找上一个节点
func (obj *Client) Prev(election ...string) *Client {
	if len(election) == 0 {
		return &Client{object: obj.object.Prev(), baseUrl: obj.baseUrl}
	} else {
		return &Client{object: obj.object.PrevFiltered(election[0]), baseUrl: obj.baseUrl}
	}
}

// 寻找之前的所有节点
func (obj *Client) Prevs(election ...string) []*Client {
	ll := []*Client{}
	var rs *goquery.Selection
	if len(election) == 0 {
		rs = obj.object.PrevAll()
	} else {
		rs = obj.object.PrevAllFiltered(election[0])
	}
	for i := 0; i < rs.Size(); i++ {
		ll = append(ll, &Client{object: rs.Eq(i), baseUrl: obj.baseUrl})
	}
	return ll
}

// 寻找所有兄弟节点
func (obj *Client) Sibs(election ...string) []*Client {
	ll := []*Client{}
	var rs *goquery.Selection
	if len(election) == 0 {
		rs = obj.object.Siblings()
	} else {
		rs = obj.object.SiblingsFiltered(election[0])
	}
	for i := 0; i < rs.Size(); i++ {
		ll = append(ll, &Client{object: rs.Eq(i), baseUrl: obj.baseUrl})
	}
	return ll
}

// 寻找所有直接子节点
func (obj *Client) Childrens(election ...string) []*Client {
	ll := []*Client{}
	var rs *goquery.Selection
	if len(election) == 0 {
		rs = obj.object.Children()
	} else {
		rs = obj.object.ChildrenFiltered(election[0])
	}
	for i := 0; i < rs.Size(); i++ {
		ll = append(ll, &Client{object: rs.Eq(i), baseUrl: obj.baseUrl})
	}
	return ll
}

// 寻找所有子节点
func (obj *Client) ChildrensAll(election ...string) []*Client {
	ll := []*Client{}
	for _, chs := range obj.Childrens(election...) {
		ll = append(ll, chs)
		ll = append(ll, chs.ChildrensAll()...)
	}
	return ll
}

// 寻找所有内容节点
func (obj *Client) Contents(election ...string) []*Client {
	ll := []*Client{}
	var rs *goquery.Selection
	if len(election) == 0 {
		rs = obj.object.Contents()
	} else {
		rs = obj.object.ContentsFiltered(election[0])
	}
	for i := 0; i < rs.Size(); i++ {
		ll = append(ll, &Client{object: rs.Eq(i), baseUrl: obj.baseUrl})
	}
	return ll
}

// 返回所有节点的字符串
func (obj *Client) Strings() []string {
	results := []string{}
	for _, kk := range obj.Contents() {
		results = append(results, kk.Text())
	}
	return results
}

// 返回父节点
func (obj *Client) Parent(election ...string) *Client {
	if len(election) == 0 {
		return &Client{object: obj.object.Parent(), baseUrl: obj.baseUrl}
	} else {
		return &Client{object: obj.object.ParentFiltered(election[0]), baseUrl: obj.baseUrl}
	}
}

// 返回所有父节点
func (obj *Client) Parents(election ...string) []*Client {
	ll := []*Client{}
	var rs *goquery.Selection
	if len(election) == 0 {
		rs = obj.object.Parents()
	} else {
		rs = obj.object.ParentsFiltered(election[0])
	}
	for i := 0; i < rs.Size(); i++ {
		ll = append(ll, &Client{object: rs.Eq(i), baseUrl: obj.baseUrl})
	}
	return ll
}

// 判断元素是否包含节点
func (obj *Client) Has(obj2 *Client) bool {
	if obj.object.Size() < 1 {
		return false
	} else {
		return obj.object.Contains(obj2.object.Nodes[0])
	}
}

// 在节点中的头部添加节点
func (obj *Client) Prepend(str string) *Client {
	return &Client{object: obj.object.PrependHtml(str), baseUrl: obj.baseUrl}
}

// 在节点中的末尾添加节点
func (obj *Client) Append(str string) *Client {
	return &Client{object: obj.object.AppendHtml(str), baseUrl: obj.baseUrl}
}

// 在节点之后添加节点
func (obj *Client) After(str string) *Client {
	return &Client{object: obj.object.AfterHtml(str), baseUrl: obj.baseUrl}
}

// 在节点之前添加节点
func (obj *Client) Before(str string) *Client {
	return &Client{object: obj.object.BeforeHtml(str), baseUrl: obj.baseUrl}
}

// 替换节点
func (obj *Client) Replace(str string) *Client {
	return &Client{object: obj.object.ReplaceWithHtml(str), baseUrl: obj.baseUrl}
}

// 复制节点
func (obj *Client) Copy() *Client {
	return &Client{object: obj.object.Clone(), baseUrl: obj.baseUrl}
}

// 删除节点
func (obj *Client) Remove() *Client {
	return &Client{object: obj.object.Remove(), baseUrl: obj.baseUrl}
}

// 清空节点内容
func (obj *Client) Clear() *Client {
	return &Client{object: obj.object.Empty(), baseUrl: obj.baseUrl}
}

// 返回节点内容或设置节点内容
func (obj *Client) Text(str ...string) string {
	if len(str) == 0 {
		return obj.object.Text()
	} else {
		return obj.object.SetText(str[0]).Text()
	}
}

// 返回节点名称或设置节点名称
func (obj *Client) Name(str ...string) string {
	if len(str) == 0 {
		return goquery.NodeName(obj.object)
	}
	if len(obj.object.Nodes) > 0 {
		obj.object.Nodes[0].Data = str[0]
	}
	return ""
}

// 返回节点的dom 字符串或设置节点的dom
func (obj *Client) Html(str ...string) string {
	var html string
	if len(str) == 0 {
		html, _ = goquery.OuterHtml(obj.object)
	} else {
		html, _ = goquery.OuterHtml(obj.object.SetHtml(str[0]))
	}
	return html
}

// 获取节点的属性
func (obj *Client) Get(key string, defaultValue ...string) string {
	if len(defaultValue) == 0 {
		val, ok := obj.object.Attr(key)
		if !ok {
			return val
		}
		switch key {
		case "href", "src":
			val2, err := tools.UrlJoin(obj.baseUrl, val)
			if err != nil {
				return val
			}
			return val2
		default:
			return val
		}
	}
	return obj.object.AttrOr(key, defaultValue[0])
}

// 设置节点的属性
func (obj *Client) Set(key string, val string) *Client {
	return &Client{object: obj.object.SetAttr(key, val), baseUrl: obj.baseUrl}
}

// 删除节点的属性
func (obj *Client) Del(key string) *Client {
	return &Client{object: obj.object.RemoveAttr(key), baseUrl: obj.baseUrl}
}

// 返回节点的所有属性
func (obj *Client) Attrs() map[string]string {
	if len(obj.object.Nodes) == 0 {
		return nil
	}
	result := map[string]string{}
	for _, node := range obj.object.Nodes[0].Attr {
		result[node.Key] = node.Val
	}
	return result
}
